package com.lox.tool;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;

//生成AST抽象语法树 此处需要修复
public class GenerateAst
{
    public static void main(String[] args) throws IOException
    {
        if(args.length != 1)
        {
            System.err.println("Usage: generate <output directory>");
            System.exit(64);
        }
        String outputDir = args[0];
        System.out.println(outputDir);
        defineAst(outputDir, "Expr", Arrays.asList(
          "Binary   : Expr left, Token operator, Expr right",
           // 新增部分开始
          "Call     : Expr callee, Token paren, List<Expr> arguments",
      // 新增部分结束
          "Grouping : Expr expression",
          "Literal  : Object value",
          "Unary    : Token operator, Expr right"
        ));

    }
    private static void defineAst(String outputDir, String baseName, List<String> types) throws IOException
    {
        String path = outputDir + "/" + baseName + ".java";
        PrintWriter writer = new PrintWriter(path,"UTF-8");

        writer.println("package com.lox");
        writer.println();
        writer.println("import java.util.List;");
        writer.println("abstract class " + baseName + " {");
        //新增部分
        defineVisitor(writer, baseName, types);

        //新增结束
        //the AST classes.
        for(String type :types)
        {
            String className = type.split(":")[0].trim();
            String fields = type.split(":")[1].trim();
            defineType(writer, baseName, className, fields);
        }
        //新增部分开始
        // The base accept() method.
        writer.println();
        writer.println("  abstract <R> R accept(Visitor<R> visitor);");
        //新增部分结束
        writer.println("}");
        writer.close();
    }
    private static void defineVisitor(
        PrintWriter writer, String baseName, List<String> types) {
      writer.println("  interface Visitor<R> {");
  
      for (String type : types) {
        String typeName = type.split(":")[0].trim();
        writer.println("    R visit" + typeName + baseName + "(" +
            typeName + " " + baseName.toLowerCase() + ");");
      }
  
      writer.println("  }");
    }
    private static void defineType(PrintWriter writer, String baseName, String className, String fieldList)
    {
        writer.println("  static class " + className + " extends " +
        baseName + " {");

        // Constructor.
        writer.println("    " + className + "(" + fieldList + ") {");
        
         // Store parameters in fields.
        String[] fields = fieldList.split(", ");
        for (String field : fields) 
        {
            String name = field.split(" ")[1];
            writer.println("      this." + name + " = " + name + ";");
        }

        writer.println("    }");
        // 新增部分开始
        // Visitor pattern.
        writer.println();
        writer.println("    @Override");
        writer.println("    <R> R accept(Visitor<R> visitor) {");
        writer.println("      return visitor.visit" +
            className + baseName + "(this);");
        writer.println("    }");
        // 新增部分结束
        // Fields.
        writer.println();
        for(String field : fields) 
        {
            writer.println("    final " + field + ";");
        }

        writer.println("  }");
    }
}